import 'dart:math';
import 'package:sleep/config.dart';
import 'package:sleep/db/merroy_db.dart';

enum WaveType {
  none,
  peak, //波峰
  valley, //波谷
  topPeak, //二次的波峰
  topValley, //二次的波谷
}

class WavePoint {
  final double x;
  final double y;
  final WaveType? type;

  WavePoint(this.x, this.y, {this.type});

  WavePoint copyWith({
    double? x,
    double? y,
    WaveType? type,
  }) {
    return WavePoint(x ?? this.x, y ?? this.y, type: type ?? this.type);
  }
}

enum FatigueWaveType { positive, negative }

abstract class WaveModel {
  bool isAdd = false;
}

class SingeWaveModel extends WaveModel {
  final FatigueWaveType type;
  final WavePoint peak;
  final WavePoint start;
  final WavePoint end;

  SingeWaveModel({
    required this.type,
    required this.peak,
    required this.start,
    required this.end,
  });
}

class WholeWave {
  final SingeWaveModel open;
  final SingeWaveModel close; //闭眼 吸气
  final WholeWave? before;

  WholeWave(this.open, this.close, this.before);
}

class SleepWave extends WholeWave {
  @override
  final SleepWave? before;

  double? _ri;

  SleepWave(open, close, this.before) : super(open, close, before);

  double start() {
    return close.start.x;
  }

  //呼吸频率
  double? pr() {
    if (before == null) return null;
    final va = 60 / t1()!;

    return va > 30 ? 30 : va;
  }

  double? t1() {
    if (before == null) return null;

    return (close.end.x - before!.close.end.x) * kperSecomd;
  }

  //一个周期呼吸暂停时间
  double st() {
    if (before == null) return 0;
    final bTime = (close.start.x - before!.open.end.x) * kperSecomd;
    final mTime = (open.start.x - close.end.x) * kperSecomd;
    return (bTime + mTime) <= 0 ? 0 : (bTime + mTime).abs();
  }

  bool isRealSt() {
    if (st() > 10) return true;
    return false;
  }

  setRi(double ri) {
    _ri = ri;
  }

  //
  bool isLowRi() {
    if (_ri != null) return close.peak.y / _ri! < 0.5;
    return false;
  }

  double time() {
    return (open.end.x - close.start.x) * kperSecomd;
  }

  double vhight() {
    return close.peak.y;
  }

  isStand() {
    final mybf = pr();
    if (mybf == null) return false;
    return true;
  }

  // static List<String> toKey() {
  //   return ['RR', 'T1', 'AT', 'RI'];
  // }

  // List<String> toValue() {
  //   final prStr = pr()?.toStringAsFixed(1) ?? "-";

  //   final t1Str = t1()?.toStringAsFixed(1) ?? "-";
  //   final stStr = st()?.toStringAsFixed(1) ?? "-";

  //   final riStr = (vhight() ?? 0) / (MerroyDB.share().sleepValue ?? 100) * 100;
  //   return [prStr, t1Str, stStr, riStr.toStringAsFixed(0)];
  // }
}

class FatigueWave extends WholeWave {
  @override
  final FatigueWave? before;

  FatigueWave(open, close, this.before) : super(open, close, before);

  double start() {
    return close.start.x;
  }

  double end() {
    return close.end.x;
  }

  //持续时间
  double bd() {
    return (open.end.x - close.start.x) * kperSecomd * 0.9;
  }

  //眨眼频率
  double? bf() {
    if (before == null) return null;
    final value = 60 / ((start() - before!.start()) * kperSecomd);
    return value > 60 ? 60 : value;
  }

  double vhight() {
    return close.peak.y;
  }

  //闭眼时间
  double ct() {
    final ctVal = (open.start.x - close.end.x) * kperSecomd;
    if (ctVal < 0) {
      return 0;
    }
    return ctVal;
  }

  //眼睛闭合百分比
  double? perclose() {
    if (before == null) return null;
    final value = (ct() / ((end() - before!.end()) * kperSecomd)) * 100;
    return value >= 90 ? 90 : value;
  }

  isStand() {
    final mybf = bf();
    if (mybf == null) return false;
    // if (mybf > 60) return true;
    return true;
  }
}

class PulseWaveModel extends WaveModel {
  final List<WavePoint> peakPoints; //上一个波的波谷+ 波峰 + 波谷

  WavePoint? v0;
  WavePoint? v1;
  WavePoint? v2;
  WavePoint? v3;
  WavePoint? p0;
  WavePoint? p1;
  WavePoint? p2;
  double pm;
  double? hrvPoint;
  double? _min;
  double? _max;
  PulseWaveModel(this.peakPoints, this.pm) {
    //波si
    List peaks = peakPoints
        .where((e) => (e.type == WaveType.peak || e.type == WaveType.topPeak))
        .toList();
    List valleys = peakPoints
        .where(
            (e) => (e.type == WaveType.valley || e.type == WaveType.topValley))
        .toList();

    if (peaks.length >= 3 && valleys.length >= 3) {
      v0 = valleys.removeAt(0);
      p0 = peaks.removeAt(0);

      v1 = valleys.isNotEmpty ? valleys.removeAt(0) : null;
      p1 = peaks.isNotEmpty ? peaks.removeAt(0) : null;

      v2 = valleys.length == 2 ? valleys.removeAt(0) : null;
      p2 = peaks.isNotEmpty ? peaks.removeLast() : null;
    }
  }

  get lastPointX {
    return peakPoints.last.x;
  }

  double? uT() {
    if (isStandard) {
      return toSecond((p0!.x - v0!.x) * kperSecomd);
    }
    return null;
  }

  double? k() {
    if (isStandard) {
      final pM = pm / (peakPoints.last.x - peakPoints.first.x);
      return (pM - v0!.y) / (p0!.y - v0!.y);
    }
    return null;
  }

  double? lvet() {
    if (isStandard) {
      return toSecond((v2!.x - v0!.x) * kperSecomd);
    }
    return null;
  }

  double? rWTT() {
    if (isStandard) {
      final rwtt = toSecond((p1!.x - p0!.x) * kperSecomd);
      return rwtt;
    }
    return null;
  }

  double? ai() {
    if (isStandard) {
      final ai = (p1!.y - minV()) / (p0!.y - minV());
      return ai;
    }
    return null;
  }

  double? pPT() {
    if (isStandard) {
      final ppt = (p2!.x - p0!.x) * kperSecomd;
      return toSecond(ppt);
    }
    return null;
  }

  double? lIVE() {
    if (isStandard) {
      return toSecond((v2!.x - v0!.x) * kperSecomd);
    }
    return null;
  }

  toSecond(double value) {
    return value;
  }

  @override
  String toString() {
    return 'rWTT:${rWTT()},pPT:${pPT()}';
  }

  double? bpm() {
    //50 ~ 120
    if (isStandard) {
      return min(max(60 / time, 50), 120);
    }
    return null;
  }

  double minV() {
    if (_min != null) {
      return _min!;
    }

    _min = peakPoints.first.y;
    for (final p in peakPoints) {
      _min = min(_min!, p.y);
    }
    return _min!;
  }

  double maxV() {
    if (_max != null) {
      return _max!;
    }

    _max = peakPoints.first.y;
    for (final p in peakPoints) {
      _max = max(_max!, p.y);
    }

    return _max!;
  }

  //是不是标准波
  bool get isStandard {
    //都有值，在范围内就认为是标准
    bool allValue = v0 != null &&
        v1 != null &&
        v2 != null &&
        p0 != null &&
        p1 != null &&
        p2 != null;

    if (allValue == false) {
      return false;
    }
    //幅度
    final v = (maxV() - minV()) > 0.1;

    return allValue && v && time > kminPeakTime && time < kmaxPeakTime;
  }

  double get time {
    final t = (peakPoints.last.x - peakPoints.first.x) * kperSecomd; //s
    return min(1.2, max(0.5, t));
  }

  double? get toPeakIndex {
    return p0?.x;
  }

  updateHrv(double? hrv) {
    hrvPoint = hrv;
  }

  double? get hrv {
    return hrvPoint;
  }
}
